﻿using System.Collections.Generic;

namespace DimensionsHelper.Common.Metadata.Script;

/// <summary>
///     表达式中的字符串。
/// </summary>
public class ExpressionString : ExpressionBasicType
{
    /// <summary>
    ///     表达式中的字符串。
    /// </summary>
    public ExpressionString(string value) : base(BasicTypes.String)
    {
        Value = value;
    }

    /// <summary>
    ///     表达式字符串的原始字符串。
    /// </summary>
    public string Value { get; }

    public override object GetValue(BasicTypes type)
    {
        switch (type)
        {
            case BasicTypes.Integer:
                return int.TryParse(Value, out int integer)
                    ? integer
                    : throw ThrowHelper.TypeConvertFailed("String", type.ToString());
            case BasicTypes.Double:
                return double.TryParse(Value, out double db)
                    ? db
                    : throw ThrowHelper.TypeConvertFailed("String", type.ToString());
            case BasicTypes.String:
                return Value;
            case BasicTypes.Boolean:
                return bool.TryParse(Value, out bool bln)
                    ? bln
                    : throw ThrowHelper.TypeConvertFailed("String", type.ToString());
            case BasicTypes.Categorical:
                return Categorical.TryParse(Value, out Categorical cat)
                    ? cat
                    : throw ThrowHelper.TypeConvertFailed("String", type.ToString());
            default:
                throw ThrowHelper.TypeConvertFailed("String", type.ToString());
        }
    }

    public override bool CanImplicitlyConvert(BasicTypes type)
    {
        switch (type)
        {
            case BasicTypes.Integer:
                return !double.TryParse(Value, out _) && int.TryParse(Value, out _);
            case BasicTypes.Double:
                return double.TryParse(Value, out _);
            case BasicTypes.String:
                return true;
            case BasicTypes.Boolean:
                return bool.TryParse(Value, out _);
            case BasicTypes.Categorical:
                return Categorical.TryParse(Value, out _);
            case BasicTypes.Null:
                return string.IsNullOrEmpty(Value);
            default:
                return false;
        }
    }

    public override int Compare(ExpressionBasicType expression)
    {
        if (expression.Type == BasicTypes.Null)
        {
            return string.IsNullOrEmpty(Value) ? 0 : 1;
        }

        if (int.TryParse(Value, out int integer))
        {
            int ires = integer - ((ExpressionInteger)expression.ConvertTo(BasicTypes.Integer)).Value;
            return ires > 0 ? 1 : ires == 0 ? 0 : -1;
        }

        if (double.TryParse(Value, out double db))
        {
            double dres = db - ((ExpressionDouble)expression.ConvertTo(BasicTypes.Double)).Value;
            return dres > 0 ? 1 : dres == 0 ? 0 : -1;
        }

        if (Categorical.TryParse(Value, out Categorical categorical))
        {
            return categorical.Compare(expression);
        }

        return Comparer<string>.Default.Compare(Value,
            ((ExpressionString)expression.ConvertTo(BasicTypes.String)).Value);
    }

    public override ExpressionBasicType ConvertTo(BasicTypes type)
    {
        switch (type)
        {
            case BasicTypes.Integer:
                return int.TryParse(Value, out int integer)
                    ? new ExpressionInteger(integer)
                    : throw ThrowHelper.TypeConvertFailed(Value, "Integer");
            case BasicTypes.Double:
                return double.TryParse(Value, out double db)
                    ? new ExpressionDouble(db)
                    : throw ThrowHelper.TypeConvertFailed(Value, "Double");
            case BasicTypes.String:
                return this;
            case BasicTypes.Boolean:
                return bool.TryParse(Value, out bool bln)
                    ? new ExpressionBoolean(bln)
                    : throw ThrowHelper.TypeConvertFailed(Value, "Bool");
            case BasicTypes.Categorical:
                return Categorical.TryParse(Value, out Categorical categorical)
                    ? categorical
                    : throw ThrowHelper.TypeConvertFailed(Value, "Categorical");
            default:
                throw ThrowHelper.TypeConvertFailed("String", type.ToString());
        }
    }

    public override ExpressionBasicType Add(ExpressionBasicType expression)
    {
        return new ExpressionString(Value + ((ExpressionString)expression.ConvertTo(BasicTypes.String)).Value);
    }

    public override ExpressionBasicType Divide(ExpressionBasicType expression)
    {
        throw ThrowHelper.UnsupportedOperatorOfTypes("-", "String", "String");
    }

    public override ExpressionBasicType Modulo(ExpressionBasicType expression)
    {
        throw ThrowHelper.UnsupportedOperatorOfTypes("Mod", "String", "String");
    }

    public override ExpressionBasicType Multiply(ExpressionBasicType expression)
    {
        throw ThrowHelper.UnsupportedOperatorOfTypes("*", "String", "String");
    }

    public override ExpressionBasicType Subtract(ExpressionBasicType expression)
    {
        throw ThrowHelper.UnsupportedOperatorOfTypes("/", "String", "String");
    }

    public override string ToString()
    {
        return Value;
    }
}